package main

// TODO: support multiple line text
// merge to one line ??
// bug in vim: text contains %

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
	"unicode"

	"github.com/volcengine/volc-sdk-golang/base"
)

const (
	// https://console.volcengine.com/iam/keymanage/
	kAccessKey      = "AKLTNjk2N2MyMGE1OGNiNGUzNzg0NzI1OTI2ZTg5NjViNGY"
	kSecretKey      = "WkRNMFpUVTRNbU5tWTJNeE5ERTFZemsyTlRZeU9UazNNVEkxTkRBNE5EUQ=="
	kServiceVersion = "2020-06-01"
)

type txtType int
const (
	chineseText txtType = iota
	englishText
)

type Req struct {
	SourceLanguage string   `json:"SourceLanguage"`
	TargetLanguage string   `json:"TargetLanguage"`
	TextList       []string `json:"TextList"`
}

type Response struct {
	TranslationList []struct {
		Translation            string `json:"Translation"`
		DetectedSourceLanguage string `json:"DetectedSourceLanguage"`
		Extra                  struct {
			InputCharacters string `json:"input_characters"`
			SourceLanguage  string `json:"source_language"`
		} `json:"Extra"`
	} `json:"TranslationList"`
	ResponseMetadata struct {
		RequestId string `json:"RequestId"`
		Action    string `json:"Action"`
		Version   string `json:"Version"`
		Service   string `json:"Service"`
		Region    string `json:"Region"`
	} `json:"ResponseMetadata"`
	ResponseMetaData struct {
		RequestId string `json:"RequestId"`
		Action    string `json:"Action"`
		Version   string `json:"Version"`
		Service   string `json:"Service"`
		Region    string `json:"Region"`
	} `json:"ResponseMetaData"`
}

var (
	ServiceInfo = &base.ServiceInfo{
		Timeout: 5 * time.Second,
		Host:    "translate.volcengineapi.com",
		Header: http.Header{
			"Accept": []string{"application/json"},
		},
		Credentials: base.Credentials{Region: base.RegionCnNorth1, Service: "translate"},
	}
	ApiInfoList = map[string]*base.ApiInfo{
		"TranslateText": {
			Method: http.MethodPost,
			Path:   "/",
			Query: url.Values{
				"Action":  []string{"TranslateText"},
				"Version": []string{kServiceVersion},
			},
		},
	}
)

// hasChinese Check if the string contains Chinese characters
func hasChinese(s string) bool {
	for _, r := range s {
		if unicode.Is(unicode.Han, r) {
			return true
		}
	}
	return false
}

// extractParts Extract the beginning, middle and end of a string
func extractParts(s string, ttype txtType) (string, string, string) {
	runes := []rune(s) // Convert string to rune slice to handle Chinese correctly
	length := len(runes)

	stopScan := func(r rune, ttype txtType) bool {
		if ttype == chineseText {
			if unicode.Is(unicode.Han, r) {
				return true
			}
		} else {
			if unicode.IsLetter(r) {
				return true
			}
		}

		return false
	}

	// Extract the English part at the beginning
	startEnglish := ""
	startIndex := 0
	for i := 0; i < length; i++ {
		if stopScan(runes[i], ttype) {
			break
		}

		startEnglish += string(runes[i])
		startIndex = i + 1
	}

	// Extract the English part of the tail
	endEnglish := ""
	endIndex := length
	for i := length - 1; i >= 0; i-- {
		if stopScan(runes[i], ttype) {
			break
		}
		endEnglish = string(runes[i]) + endEnglish
		endIndex = i
	}

	// Extract the middle part
	middlePart := string(runes[startIndex:endIndex])

	return startEnglish, middlePart, endEnglish
}

func main() {
	var input string
	var lines []string

	// Check for pipeline input
	stat, _ := os.Stdin.Stat()
	if (stat.Mode() & os.ModeCharDevice) == 0 {
		// Read input from pipeline
		reader := bufio.NewReader(os.Stdin)
		for {
			line, err := reader.ReadString('\n')
			if err != nil && err != io.EOF {
				fmt.Fprintf(os.Stderr, "Failed to read pipe input: %v\n", err)
				os.Exit(1)
			}

			lines = append(lines, line)
			if err == io.EOF {
				break
			}
		}

		// todo: for multi line
		input = lines[0]
	} else if len(os.Args) > 1 {
		// 从命令行参数获取输入
		args := os.Args[1:]
		if len(args) == 0 {
			fmt.Println("Please provide at least one argument")
			os.Exit(1)
		}
		input = strings.Join(args, " ")

	} else {
		fmt.Println("Please provide at least one argument")
		os.Exit(1)
	}

	textList := []string{}

	client := base.NewClient(ServiceInfo, ApiInfoList)
	client.SetAccessKey(kAccessKey)
	client.SetSecretKey(kSecretKey)

	req := Req{}
	start := ""
	mid := ""
	end := ""

	if hasChinese(input) {
		req.SourceLanguage = "zh"
		req.TargetLanguage = "en"
		start, mid, end = extractParts(input, chineseText)
		textList = append(textList, mid)
		req.TextList = textList
	} else {
		req.SourceLanguage = "en"
		req.TargetLanguage = "zh"
		start, mid, end = extractParts(input, englishText)
		textList = append(textList, mid)
		req.TextList = textList
	}

	body, _ := json.Marshal(req)
	resp, code, err := client.Json("TranslateText", nil, string(body))
	if err != nil {
		fmt.Printf("json error: %v \n", err)
		os.Exit(1)
	}

	if code != 200 {
		fmt.Printf("http code error: %d \n", code)
		os.Exit(1)
	}

	var response Response
	// Parsing JSON data
	err = json.Unmarshal([]byte(resp), &response)
	if err != nil {
		fmt.Printf("parse json failed: %v\n", err)
		os.Exit(1)
	}

	// Extracting Translation Information
	for _, item := range response.TranslationList {
		fmt.Printf("%s%s%s\n", start, item.Translation, end)
	}
}
